package odgs.manager;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import odgs.Acceptor;
import odgs.Connection;
import odgs.Result;
import odgs.app.GridServer;
import odgs.listener.AcceptorListener;
import odgs.listener.ConnectionListener;
import odgs.listener.NetworkManagerListener;
import odgs.message.Message;
import odgs.pda.PdaConnection;

public class NetworkManager implements AcceptorListener, ConnectionListener
{
	private List<NetworkManagerListener> networkListeners = new ArrayList<NetworkManagerListener>();
	private Thread acceptor;
	private List<Connection> connections = new ArrayList<Connection>();
	private Connection serverConnection;
	private boolean isOpen = false;
	private ResourceManager	resourceManager;

	public boolean open(int port, int portPDA)
	{
		try
		{
			Acceptor acceptors = new Acceptor(port, Acceptor.PC);
			acceptors.addAcceptorListener(this);
			acceptor = new Thread(acceptors);
			acceptor.start();
			
			Acceptor pdaAcceptor = new Acceptor(portPDA, Acceptor.PDA);
			pdaAcceptor.addAcceptorListener(this);
			new Thread(pdaAcceptor).start();
			
			
			isOpen = true;
			notifyServerOpened(port);
			return isOpen;
		}
		catch (IOException e)
		{
			notifyError(Result.SERVER_CAN_NOT_OPEN);
			return false;
		}
	}
	
	private void notifyServerOpened(int port)
	{
		List<NetworkManagerListener> ls = getSnapshotNetworkManagerListeners();
		for(NetworkManagerListener l : ls)
		{
			l.opened(port);
		}
	}

	private List<NetworkManagerListener> getSnapshotNetworkManagerListeners()
	{
		return new ArrayList<NetworkManagerListener>(networkListeners);
	}

	private void notifyError(int error)
	{
		List<NetworkManagerListener> ls = getSnapshotNetworkManagerListeners();
		for(NetworkManagerListener l : ls)
		{
			l.error(error);
		}
	}

	public int getConnectionSize()
	{
		return connections.size();
	}

	private void notifyConnetedEvent(Connection con)
	{
		List<NetworkManagerListener> ls = getSnapshotNetworkManagerListeners();
		for(NetworkManagerListener l : ls)
		{
			l.connected(con);
		}
	}

	public void addNetworkManagerListener(NetworkManagerListener listener)
	{
		networkListeners.add(listener);
	}

	public void connectToServer(String ip, int port)
	{
		try
		{
			Socket socket = new Socket(ip,port);
			serverConnection = new Connection(socket);
			serverConnection.setType(Connection.SERVER);
			serverConnection.addConnectionListener(this);
			notifyServerConnectedEvent(serverConnection);
		}
		catch (Exception e) 
		{
			e.printStackTrace(); 
			error(Result.SERVER_IS_NOT_OPEN);
		}
	}

	private void error(int error)
	{
		List<NetworkManagerListener> ls = getSnapshotNetworkManagerListeners();
		for(NetworkManagerListener l : ls)
		{
			l.error(error);
		}
	}

	private void notifyServerConnectedEvent(Connection connection)
	{
		List<NetworkManagerListener> ls = getSnapshotNetworkManagerListeners();
		for(NetworkManagerListener l : ls)
		{
			l.connectedServer(connection);
		}
	}

	public Connection getServerConnection()
	{
		return serverConnection;
	}

	public Connection connect(String ip, int port)
	{
		Socket socket;
		try
		{
			socket = new Socket(ip,port);
			Connection temp = new Connection(socket,Connection.FILE_NOT_MESSAGE_RECEIVE);
			temp.addConnectionListener(this);
			temp.setResouceManager(resourceManager);
			connections.add(temp);
			notifyConnetedEvent(temp);
			return temp;
		} 
		catch (Exception e)
		{
			notifyError(Result.SERVER_IS_NOT_OPEN);
			return null;
		}
	}

	public void disconnected(Connection con)
	{
		System.out.println("NetworkManager.disconnected()");
		List<NetworkManagerListener> ls = getSnapshotNetworkManagerListeners();
		for(NetworkManagerListener l : ls)
		{
			if(con.getType() == Connection.SERVER)
			{
				serverConnection = null;
				l.disconnectedServer(con);
			}
			else
			{
				connections.remove(con);
				l.disconnected(con);
			}
		}
	}

	public Connection getConnection(String ip)
	{
		for(Connection con : connections)
		{
			if(con.getIP().equals(ip))
				return con;
		}
		return null;
	}

	public boolean isOpenServer()
	{
		return isOpen;
	}

	public void broadcastMessage(Message reMsg)
	{
		List<Connection> cons = getSnapshotConnections();
		for(Connection con : cons)
		{
			con.sendMessage(reMsg);
		}
	}

	private List<Connection> getSnapshotConnections()
	{
		return new ArrayList<Connection>(connections);
	}

	public void setResourceManager(ResourceManager resourceManager)
	{
		this.resourceManager = resourceManager;
	}
	
	public void accepted(Socket socket)
	{
		Connection con = new Connection(socket);
		con.setResouceManager(resourceManager);
		con.addConnectionListener(this);
		connections.add(con);
		notifyConnetedEvent(con);
	}

	public void pdaAccepted(Socket socket) {
		Connection con = new PdaConnection(socket);
		con.setResouceManager(resourceManager);
		con.addConnectionListener(this);
		connections.add(con);
		notifyConnetedEvent(con);
	}

	public String getLocalIP()
	{
		return null;
	}
}